package edu.kpi.pzks2.ui.task;

import java.awt.Component;
import java.awt.Font;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

import org.apache.commons.collections15.Transformer;

import edu.kpi.pzks2.graph.Edge;
import edu.kpi.pzks2.graph.Node;
import edu.kpi.pzks2.tools.GenerationParams;
import edu.kpi.pzks2.tools.TaskGraphTools;
import edu.kpi.pzks2.ui.GraphEditor;
import edu.kpi.pzks2.ui.MainFrame;
import edu.kpi.pzks2.ui.dialogs.WeightDialog;
import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.VertexLabelRenderer;

@SuppressWarnings("serial")
public class TaskEditor  extends GraphEditor {
    
    public Graph<Node, Edge> getNeededGraph() {
        return new DirectedSparseGraph<Node, Edge>();
    }
    
    public TaskEditor() {
        super();
        
        visual.addMouseListener(new  MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                GraphElementAccessor<Node,Edge> pickSupport = visual.getPickSupport();
                if (e.getClickCount() == 2) {
                    final Node node = pickSupport.getVertex(visual.getGraphLayout(), e.getX(), e.getY());
                    if (node != null) {
                        final WeightDialog dia = new WeightDialog(node, visual);
                        dia.setVisible(true);
                        return;
                    }
                    
                    final Edge edge = pickSupport.getEdge(visual.getGraphLayout(), e.getX(), e.getY());
                    if (edge != null) {
                        final WeightDialog dia = new WeightDialog(edge, visual);
                        dia.setVisible(true);
                    }
                }
            }
        });
        
        visual.getRenderContext().setVertexLabelRenderer(new VertexLabelRenderer() {
            public <T> Component getVertexLabelRendererComponent(JComponent vv,
                    Object value, Font font, boolean isSelected, T vertex) {
                final JPanel panel = new JPanel(new MigLayout("insets 0 0 0 0", "[align center]", "[]0[]"));
                
                panel.setOpaque(false);
                
                panel.add(new JLabel("#" + ((Node) vertex).getId()), "cell 0 0");
                panel.add(new JLabel("" + ((Node) vertex).getWeight()), "cell 0 1");
                
                return panel;
            }
        });
        
        visual.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>() {
            @Override
            public String transform(Node v) {
                return "#" + v.getVisualOrderNumber() + "\n" + v.getWeight();
            }
        });
        visual.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<Edge>() {
            @Override
            public String transform(Edge v) {
                return Integer.toString(v.getWeight());
            }
        });

        final Transformer<Node, Shape> shapeVertexPaint = new Transformer<Node,Shape>() {
            public Shape transform(Node arg0) {
             float size = 40;
                      return new Ellipse2D.Float(-(size/2f), -(size/2f), size, size);
            }
        };
        visual.getRenderContext().setVertexShapeTransformer(shapeVertexPaint);
    }

    public boolean isGraphValid() {
        DirectedGraph<Node, Edge> graph = (DirectedGraph<Node, Edge>) getGraphLayout().getGraph();
        
        boolean dontHaveCycles = TaskGraphTools.dontHaveLoops(graph);
        
        if (!dontHaveCycles) {
            MainFrame.showLogMessage("Task graph has loops.");
        } else {
            MainFrame.showLogMessage("Task graph is valid.");
        }
        
        return dontHaveCycles;
    }
    
    public void generateGraph(final GenerationParams params) {
        final DirectedSparseGraph<Node, Edge> graph = TaskGraphTools.generate(params, false);
        
        nodeId = graph.getVertices().size();
        
        layout = new ISOMLayout<Node, Edge>(graph);
        visual.setGraphLayout(layout);
    }
    
    public DirectedGraph<Node, Edge> getTaskGraph() {
        return (DirectedGraph<Node, Edge>) visual.getGraphLayout().getGraph();
    }
}
